// //******************************************************// // Name: Chris Washington // // E-mail: christopherwashington@hotmail.com // // SID: 462-59-3368 // // Sect: Thursday // // // // Lab Assignment #7 - MIPS Microprocessor (pipelined) // //******************************************************// // --------------------------------------------- main module -------------------------------------------- // module mips (clk, rst_, scan_mode, scan_in, scan_out); output scan_out; // scan out bit for scan testing input clk, // system clock rst_, // reset (active low) scan_mode, // normal operation(0) or scan test(1) mode scan_in; // scan in bit for scan testing reg [7:0] PC; // program counter reg scan_out; reg [39:0] latch1; reg [123:0] latch2; reg [106:0] latch3; reg [70:0] latch4; wire [39:0] latch1_in; wire [123:0] latch2_in; wire [106:0] latch3_in; wire [70:0] latch4_in; wire [7:0] altPC; wire [7:0] PC_in; wire [4:0] write_reg; wire [31:0] write_data; parameter MSB1 = 39; parameter MSB2 = 123; parameter MSB3 = 106; parameter MSB4 = 70; // ********* COMBINATIONAL LOGIC ********* // IF IF0 (latch1_in, PC_in, PC, PCsrc, altPC); // Instruction Fetch ID ID0 (latch2_in, latch1, write_reg, write_data, RegWrite); // Instruction Decode EX EX0 (latch3_in, latch2); // Execute ME ME0 (latch4_in, PCsrc, altPC, latch3); // Memory Access (data) WB WB0 (write_data, write_reg, RegWrite, latch4); // Write Back // ********* SYNCRONIS LOGIC ********* // always @(posedge clk or negedge rst_) begin // RESET (active low) if (rst_ == 0) begin $display(" ~~~~~~~~~~~~~~~~~~ IN RESET ~~~~~~~~~~~~~~~~"); PC <= 4; latch1 <= 0; latch2 <= 0; latch3 <= 0; latch4 <= 0; $display("~~~~~~~~~~~~~~~~~~~~~~clearmem~~~~~~~~~~~~~~~~~~~~~~~~"); $readmemh("memory/CLEAR.dat", IF0.IF1.pgm_mem); // clear program memory $readmemh("memory/CLEAR.dat", ME0.ME1.data_mem); // clear data memory $display("~~~~~~~~~~~~~~~~~~~~~~loadmem~~~~~~~~~~~~~~~~~~~~~~~~~"); $readmemh("memory/DMEM.dat", ME0.ME1.data_mem); // load data memory $readmemh("memory/IMEM.dat", IF0.IF1.pgm_mem); // load program memory $display("~~~~~~~~~~~~~~~~~~~~~~donemem~~~~~~~~~~~~~~~~~~~~~~~~~"); // $display("%b %b %b %b", ME0.ME1.data_mem[4], ME0.ME1.data_mem[3], ME0.ME1.data_mem[2], ME0.ME1.data_mem[1]); // $display("%b %b %b %b", ME0.ME1.data_mem[8], ME0.ME1.data_mem[7], ME0.ME1.data_mem[6], ME0.ME1.data_mem[5]); // $display("%b %b %b %b", ME0.ME1.data_mem[12], ME0.ME1.data_mem[11], ME0.ME1.data_mem[10], ME0.ME1.data_mem[9]); // $display("%b %b %b %b", ME0.ME1.data_mem[16], ME0.ME1.data_mem[15], ME0.ME1.data_mem[14], ME0.ME1.data_mem[13]); // $display; // $display("%b %b %b %b", IF0.IF1.pgm_mem[32], IF0.IF1.pgm_mem[31], IF0.IF1.pgm_mem[30], IF0.IF1.pgm_mem[29]); // $display; // $display("%b %b %b %b", IF0.IF1.pgm_mem[116], IF0.IF1.pgm_mem[115], IF0.IF1.pgm_mem[114], IF0.IF1.pgm_mem[113]); // $stop; end else if (scan_mode == 1) // SCAN TEST MODE begin scan_out = latch4_in[MSB4]; latch4 = {latch4_in[MSB4-1:0], latch3_in[MSB3]}; latch3 = {latch3_in[MSB3-1:0], latch2_in[MSB2]}; latch2 = {latch2_in[MSB2-1:0], latch1_in[MSB1]}; latch1 = {latch1_in[MSB1-1:0], scan_in}; end else // LATCH DATA begin // $stop; $display; $display ("~~~~~~~~~~~~~~~~~~~~~~~ LATCHING ~~~~~~~~~~~~~~~~~~~~~~~~~");$display; PC <= PC_in + 4; // increment program counter latch1 <= latch1_in; latch2 <= latch2_in; latch3 <= latch3_in; latch4 <= latch4_in; // $display ("PC(post latch) = %d", PC); $display (" s0 = %b", T1.ID0.ID2.register[0]); $display (" s1 = %b", T1.ID0.ID2.register[1]); $display (" s2 = %b", T1.ID0.ID2.register[2]); $display (" s3 = %b", T1.ID0.ID2.register[3]); $display (" s4 = %b", T1.ID0.ID2.register[4]); $display (" s5 = %b", T1.ID0.ID2.register[5]); $display (" s6 = %b", T1.ID0.ID2.register[6]); $display (" s7 = %b", T1.ID0.ID2.register[7]); $display; $display ("LATCH1: PC%d Inst%b", latch1[39:32], latch1[31:0]); $display; $display ("LATCH2: WB%b M%b EX%b PC%d", latch2[123:122], latch2[121:119], latch2[118:114], latch2[113:106]); // $display (" reg_out1 %b", latch2[105:74]); // $display (" reg_out2 %b", latch2[73:42]); // $display (" inst[15:0]%b", latch2[41:10]); // $display (" inst[20:16]%b inst[4:0]%b", latch2[9:5], latch2[4:0]); // // $display(" ~~~~~~~~~~~~~~~~~~~~~~~~ ALU ~~~~~~~~~~~~~~~~~~~~~"); // $display(" alu_in1 = %d", EX0.EX2.alu_in1); // $display(" = %b", EX0.EX2.alu_in1); // $display(" alu_in2 = %d", EX0.EX2.alu_in2); // $display(" = %b", EX0.EX2.alu_in2); // $display(" ALU_result = %d", EX0.EX2.ALU_result); // $display(" = %b", EX0.EX2.ALU_result); // $display(" alu_control = %b", EX0.EX2.alu_control); // $display; // // $display ("LATCH3: WB%b M%b", latch3[106:105], latch3[104:102]); // $display (" Add_result%b", latch3[101:70]); // $display (" zero%b", latch3[69]); // $display (" ALU_result%b", latch3[68:37]); // $display (" reg_out2%b", latch3[36:5]); // $display (" latch2[4:0]%b", latch3[4:0]); // // $display ("LATCH4: WB%b", latch4[70:69]); // $display (" dmem_out%b", latch4[68:37]); // $display (" ALU_result%b", latch4[36:5]); // $display (" latch3[4:0]%b", latch4[4:0]); // // $display ("WBINFO: write_data%b", write_data); // $display (" write_reg%b", write_reg); // $display (" RegWrite%b", RegWrite); end end endmodule // --------------------------------------------- pipeline modules ------------------------------------------ // // ********* INSTRUCTION FETCH ********* // module IF (latch1_in, PC_in, PC, PCsrc, altPC); output [39:0] latch1_in; input PCsrc; // program counter source control (from ME glue logic) input [7:0] altPC; // alternate PC (from latch3[101:70]) input [7:0] PC; // program counter output [7:0] PC_in; // instruction address for next cycle wire [31:0] instruction; assign PC_in = PCsrc ? altPC : PC; pmem IF1 (instruction, PC_in); assign latch1_in = {PC_in, instruction}; endmodule // ********* INSTRUCTION DECODE ********* // module ID (latch2_in, latch1, write_reg, write_data, RegWrite); output [123:0] latch2_in; input [39:0] latch1; input [4:0] write_reg; input [31:0] write_data; input RegWrite; wire [1:0] WB; wire [4:0] EX; wire [2:0] M; wire [31:0] reg_out1, reg_out2, sgnext_out; control ID1 (WB, M, EX, latch1[31:26]); // , , , opfield registers ID2 (reg_out1, reg_out2, latch1[25:21], latch1[20:16], write_reg, write_data, RegWrite); // , , read_reg1, read_reg2, , , sign_ext ID3 (sgnext_out, latch1[15:0]); // , immediate assign latch2_in = {WB, M, EX, latch1[39:32], reg_out1, reg_out2, sgnext_out, latch1[20:16], latch1[15:11]}; // PC, instruction[20:16] [15:11] endmodule // ********* EXECUTE ********* // module EX (latch3_in, latch2); output [106:0] latch3_in; input [123:0] latch2; wire [31:0] JumpBranch_, shifted; wire [2:0] alu_control; wire [31:0] Add_result, ALU_result, alu_in2, alu_in1; wire zero; wire [4:0] dest_reg; assign alu_in1 = (~alu_control[2] & alu_control[1] & alu_control[0]) ? latch2[41:10] : latch2[105:74]; assign alu_in2 = latch2[114] ? latch2[41:10] : latch2[73:42]; // ALUSrc ? immediate : read_reg2 alu_control EX1 (alu_control, latch2[117:115], latch2[15:10]); // , aluOp, FuncField alu EX2 (ALU_result, zero, alu_control, alu_in1, alu_in2); // , , , read_reg1, shift_left_2 EX3 (shifted, latch2[41:10]); // , immediate assign JumpBranch_ = latch2[117] ? 32'b0 : latch2[113:106]; // aluOP[2] ? 32'b0 : PC assign Add_result = shifted + JumpBranch_; assign dest_reg = latch2[118] ? latch2[4:0] : latch2[9:5]; // RegDest ? instruction[15:11] | [20:16] assign latch3_in = {latch2[123:122], latch2[121:119], Add_result, zero, ALU_result, latch2[73:42], dest_reg}; endmodule // ********* DATA MEMORY ACCESS ********* // module ME (latch4_in, PCsrc, altPC, latch3); output [70:0] latch4_in; output PCsrc; output [7:0] altPC; input [106:0] latch3; wire [31:0] dmem_out; dmem ME1 (dmem_out, latch3[44:37], latch3[36:5], latch3[103],latch3[102]); // , dmem_addr, dmem_in, MemRead, MemWrite and (PCsrc,latch3[69],latch3[104]); // , zero, branch assign altPC = latch3[101:70]; // Add_result assign latch4_in = {latch3[106:105], dmem_out, latch3[68:37],latch3[4:0]}; // WB, , ALU_result, dest_reg endmodule // ********* WRITE BACK ********* // module WB (wb_data, wb_reg, wb_cntl, latch4); output [31:0] wb_data; output [4:0] wb_reg; output wb_cntl; input [70:0] latch4; assign wb_reg = latch4[4:0]; // dest_reg assign wb_data = latch4[69] ? latch4[68:37] : latch4[36:5]; // MemtoReg ? dmem_out : ALU_result assign wb_cntl = latch4[70]; // RegWrite endmodule // -------------------------------------------------- memory ---------------------------------------------- // // ********* PROGRAM MEMORY ********* // module pmem (pmem_out, pmem_addr); output [31:0] pmem_out; input [7:0] pmem_addr; reg [7:0] pgm_mem[1:200]; assign pmem_out = {pgm_mem[pmem_addr], pgm_mem[pmem_addr-1], pgm_mem[pmem_addr-2], pgm_mem[pmem_addr-3]}; endmodule // ********* DATA MEMORY ********* // module dmem (dmem_out, dmem_addr, dmem_in, MemRead, MemWrite); output [31:0] dmem_out; input [31:0] dmem_in; input [7:0] dmem_addr; input MemRead, MemWrite; reg [7:0] data_mem[1:200]; assign dmem_out[31:24] = MemRead ? data_mem[dmem_addr] : 8'bx; assign dmem_out[23:16] = MemRead ? data_mem[dmem_addr-1] : 8'bx; assign dmem_out[15:8] = MemRead ? data_mem[dmem_addr-2] : 8'bx; assign dmem_out[7:0] = MemRead ? data_mem[dmem_addr-3] : 8'bx; always @(dmem_addr or dmem_in or MemWrite) if (MemWrite == 1) // write to data memory begin $display (" **** DMEM WRITE --> addr: %d data: %b", dmem_addr, dmem_in); {data_mem[dmem_addr],data_mem[dmem_addr-1],data_mem[dmem_addr-2],data_mem[dmem_addr-3]} <= dmem_in; end endmodule // ----------------------------------------------- submodules --------------------------------------------- // // ********* MAIN CONTROL ********* // module control (WB, M, EX, opfield); output [1:0] WB; // WRITE BACK control signals output [2:0] M; // MEMORY control signals output [4:0] EX; // EXECUTE control signals input [5:0] opfield; // operation code from instruction wire of0, of1, of2, of3, of4, of5, RegWrite, MemtoReg, branch, MemRead, MemWrite, RegDst, aluOP2, aluOP1, aluOP0, aluSrc; assign of0 = opfield[0]; assign of1 = opfield[1]; assign of2 = opfield[2]; assign of3 = opfield[3]; assign of4 = opfield[4]; assign of5 = opfield[5]; assign RegWrite = ~|(opfield) | ~of5 & ~of4 & of3 & ~of2 & ~of1 & ~of0 | of5 & ~of4 & ~of3 & ~of2 & of1 & of0; // opfield = 000000 | 001000 | 100011 assign MemtoReg = of5 & ~of4 & ~of3 & ~of2 & of1 & of0; // opfield = 100011 assign branch = ~of5 & ~of4 & ~of3 & of2 & ~of1 & ~of0 | ~of5 & ~of4 & ~of3 & ~of2 & of1 & ~of0; // opfield = 000100 | 000010 assign MemRead = of5 & ~of4 & ~of3 & ~of2 & of1 & of0; // opfield = 100011 assign MemWrite = of5 & ~of4 & of3 & ~of2 & of1 & of0; // opfield = 101011 assign RegDst = ~|(opfield); // opfield = 000000 assign aluOP2 = ~of5 & ~of4 & ~of3 & ~of2 & of1 & ~of0; // opfield = 000010 assign aluOP1 = ~|(opfield); // opfield = 000000 assign aluOP0 = ~of5 & ~of4 & ~of3 & of2 & ~of1 & ~of0; // opfield = 000100 assign aluSrc = of5 & ~of4 & ~of2 & of1 & of0 | ~of5 & ~of4 & of3 & ~of2 & ~of1 & ~of0; // opfield = 000000 | 10x011 | 001000 assign WB[1] = RegWrite; assign WB[0] = MemtoReg; assign M[2] = branch; assign M[1] = MemRead; assign M[0] = MemWrite; assign EX[4] = RegDst; assign EX[3] = aluOP2; assign EX[2] = aluOP1; assign EX[1] = aluOP0; assign EX[0] = aluSrc; endmodule // ********* ALU CONTROL ********* // module alu_control (alu_control, aluOp, FuncField); output [2:0] alu_control; // alu operation code input [2:0] aluOp; // operation code from control input [5:0] FuncField; // arithmetic function field (from instruction) wire op2, op1, op0, ff5, ff4, ff3, ff2, ff1, ff0; assign op2 = aluOp[2]; assign op1 = aluOp[1]; assign op0 = aluOp[0]; assign ff5 = FuncField[5]; assign ff4 = FuncField[4]; assign ff3 = FuncField[3]; assign ff2 = FuncField[2]; assign ff1 = FuncField[1]; assign ff0 = FuncField[0]; assign alu_control[2] = (~op2 & op1 & ~op0 & ff5 & ~ff4 & ~ff3 & ~ff2 & ff1 & ~ff0) | ~op2 & ~op1 & op0 | op2 & ~op1 & ~op0; // aluOP = 010 & FuncField = 100010 | aluOP = 001 | aluOP = 100 assign alu_control[1] = ~(( op2 & ~op1 & ~op0) | (~op2 & op1 & ~op0 & ff5 & ~ff4 & ~ff3 & ff2 & ~ff1 & ~ff0)); // aluOP != 100 & != (aluOP = 010 & Funcfield = 100100) assign alu_control[0] = ~op2 & op1 & ~op0 & ~|(FuncField); // aluOP = 010 & FuncField != 000000 endmodule // ********* REGISTERS ********* // module registers (reg_out1, reg_out2, read_reg1, read_reg2, write_reg, write_data, RegWrite); output [31:0] reg_out1, reg_out2; // output register values determined by read_reg input [31:0] write_data; // data to be writen to write_reg input [4:0] read_reg1, read_reg2, // register to read from write_reg; // register to write to input RegWrite; // write to register control signal wire [31:0] regzero; reg [31:0] register[7:0]; // registers always @(write_reg or RegWrite or write_data or read_reg1 or read_reg2) begin if (RegWrite == 1) register[write_reg] = write_data; register[0] = 31'b0; // register zero never changes??? end assign reg_out1 = register[read_reg1]; // read_reg1 logic assign reg_out2 = register[read_reg2]; // read_reg2 logic endmodule // ********* SIGN EXTEND ********* // module sign_ext (sgnext_out, sgnext_in); output [31:0] sgnext_out; input [15:0] sgnext_in; assign sgnext_out = sgnext_in[15] ? {16'b1, sgnext_in[15:0]} : {16'b0, sgnext_in[15:0]}; endmodule // ********* SHIFT LEFT 2 ********* // module shift_left_2 (shifted, unshifted); output [31:0] shifted; input [31:0] unshifted; assign shifted = {unshifted[29:0], 2'b00}; endmodule // ********* ARITHMETIC LOGIC UNIT (ALU) ********* // module alu (ALU_result, zero, alu_control, alu_in1, alu_in2); output [31:0] ALU_result; // ALU result output zero; // 1 if result is zero input [2:0] alu_control; // alu operation code (from alu_control) input [31:0] alu_in1, alu_in2; // ALU operands wire [31:0] ADD, SUB, SLL, AND, STZ; wire aluc2, aluc1, aluc0; wire [4:0] shft; assign aluc2 = alu_control[2]; assign aluc1 = alu_control[1]; assign aluc0 = alu_control[0]; assign shft = alu_in1[10:6]; assign ADD = alu_in1 + alu_in2; assign SUB = alu_in1 - alu_in2; assign SLL = alu_in2 << shft; assign AND = alu_in1 & alu_in2; assign STZ = 0; assign ALU_result = (~aluc2 & aluc1 & ~aluc0) ? ADD : ( aluc2 & aluc1 & ~aluc0) ? SUB : (~aluc2 & aluc1 & aluc0) ? SLL : (~aluc2 & ~aluc1 & ~aluc0) ? AND : ( aluc2 & ~aluc1 & ~aluc0) ? STZ : 32'bz; assign zero = ALU_result ? 1'b0 : 1'b1; // 1 if result is zero endmodule